﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Linq;

namespace SharpSoft.Web
{
    public class AuthorizeProvider : Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelProvider
    {
        public static PermissionMap _PermissionMap;
        public static PermissionMap PermissionMap
        {
            get
            {
                if (_PermissionMap == null)
                {
                    throw new Exception("权限映射表尚未初始化，无法访问。");
                }
                return _PermissionMap;
            }
            private set { _PermissionMap = value; }
        }

        public int Order =>-99;

        public Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(AuthorizationHandlerContext context)
        {
            throw new NotImplementedException();
        }

        public void OnProvidersExecuted(ApplicationModelProviderContext context)
        {
        }

        private static string GetArea(IReadOnlyList<object> atts)
        {
            var areas = atts.OfType<Microsoft.AspNetCore.Mvc.AreaAttribute>().ToArray();
            if (areas.Length > 0)
            {
                return areas[0].RouteValue;
            }
            return null;
        }
        private static SharpSoft.Web.AuthorizeAttribute GetAuthorize(IReadOnlyList<object> atts)
        {
            var auths = atts.OfType<SharpSoft.Web.AuthorizeAttribute>().ToArray();
            if (auths.Length > 0)
            {
                return auths[0];
            }
            return null;
        }
        /// <summary>
        /// 根据区域 控制器  活动 来创建一个唯一的权限名称
        /// </summary>
        /// <param name="area"></param>
        /// <param name="controller"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static string CreatePermissionName(string area, string controller, string action)
        {
            return $"{area}.{controller}.{action}";
        }

        public void OnProvidersExecuting(ApplicationModelProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (AuthorizeProvider._PermissionMap == null)
            {//加载权限定义映射
                Dictionary<string, string> pernames = new Dictionary<string, string>();
                foreach (var controllerModel in context.Result.Controllers)
                {
                    string area = "";
                    string controller = controllerModel.ControllerName;
                    string action = "";
                    var auth = GetAuthorize(controllerModel.Attributes);
                    if (auth != null && auth.CheckPermission)
                    {  //在Controller上定义了需要检查权限
                        var areaD = GetArea(controllerModel.Attributes);
                        if (areaD != null)
                        {
                            area = areaD;
                        }
                        pernames.Add(CreatePermissionName(area, controller, action), controllerModel.DisplayName);
                    }

                    foreach (var actionModel in controllerModel.Actions)
                    {
                        action = actionModel.ActionName;
                        var authAction = GetAuthorize(actionModel.Attributes);
                        if (authAction != null && authAction.CheckPermission)
                        {  //在Action上定义了需要检查权限
                            var areaD = GetArea(actionModel.Attributes);
                            if (areaD != null)
                            {
                                area = areaD;
                            }
                            pernames.Add(CreatePermissionName(area, controller, action), actionModel.DisplayName);
                        }
                    }
                }
                AuthorizeProvider._PermissionMap = new PermissionMap(pernames);
            }

        }
    }
}
